package network.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import state.Globals;

/**
 * Base connection receiving thread class.  Keeps track of created children
 * 
 * @author Ian Doerr
 */
public abstract class ConnectionListenerThread extends Thread {

    private ServerSocket localSock;
    private ArrayList<SocketThread> children = new ArrayList<SocketThread>();

    /**
     * Initializes a socket to listen to the passed port
     * 
     * @param port
     * @throws IOException
     */
    public ConnectionListenerThread(int port) throws IOException
    {
        localSock = new ServerSocket(port);
    }

    @Override
    /**
     * Listens for new connections on the socket, and creates handler
     * threads for them.
     * 
     * Continues until the listenting socket is closed
     * 
     */
    public void run()
    {
    	setName("Connection Listener Thread");
    	
        while (!localSock.isClosed())
        {
            Socket newConn = null;
            try
            {
                newConn = localSock.accept();
            }
            catch (IOException ex)
            {
                //TODO:  log this!
            }
            
            if (newConn == null)
            {
                continue;
            }
            
            SocketThread handle = createChild(newConn);
            handle.start();
            
            children.add(handle);
            
        }
    }
    
    /**
     * This is the helper method for creating a new Socket Thread, and
     * needs to be implemented by subclasses.
     * 
     * @param remoteSocket
     * @return
     */
    public abstract SocketThread createChild(Socket remoteSocket);
    
    /**
     * Remove the given child thread from monitoring
     * 
     * @param thread
     */
    public void removeChild(SocketThread thread)
    {
    	children.remove(thread);
    }
    
    /**
     * Closes the listening socket, and then shuts down all of the handling threads.
     * Returns when all the threads have shut down.
     */
    public void shutdownThread()
    {
        try
        {
            localSock.close();
        }
        catch (IOException e)
        {
            Globals.getLogger().error("Error occurred while closing the listening socket!", e);
        }
        
        for (SocketThread c : children)
        {
            c.shutdownThread();
        }
        
        for (SocketThread c : children)
        {
        	try {
				c.getThread().join();
			} catch (InterruptedException e) {
				//NOOP
			}
        }
        
    	try {
			join();
		} catch (InterruptedException e) {
			//NOOP
		}
        
    }

}
